﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using JigLibX.Collision;
using JigLibX.Physics;
using JigLibX.Geometry;
using JigLibX.Math;

namespace DARE
{
    public class CCharacterController : APhysicController
    {

    #region fields

        private bool m_doJump = false;
        private Vector3 m_desiredVelocity = Vector3.Zero;
        private float m_moveSpeed = 4.0f;

        private Vector3 m_moveTo = Vector3.Zero;
        private bool m_processMove = false;
        private float m_distance = 0.0f;

        private float m_yawDirection;

    #endregion

    #region properties

        public Vector3 DesiredVelocity 
        { 
            get { return m_desiredVelocity; }
            set { m_desiredVelocity = value; }
        }

        public float MoveSpeed
        {
            get { return m_moveSpeed; }
            set { m_moveSpeed = value; }
        }

        public bool IsMoving
        {
            get { return m_processMove; }
        }

        public float YawDirection
        {
            get { return m_yawDirection; }
        }

    #endregion

    #region ctor

        /// <summary>
        /// Dont use it :D
        /// </summary>
        public CCharacterController()
        {
            Initialize();
        }

        public CCharacterController(CNode node) : 
            base(node.Entity.Physic.Body)
        {
            Initialize();
        }

        public CCharacterController(CEntity entity) : 
            base(entity.Physic.Body)
        {
            Initialize();
        }

        public CCharacterController(APhysicObject physic) : 
            base(physic.Body)
        {
            Initialize();
        }

        public CCharacterController(Body body) : 
            base(body)
        {
            Initialize();
        }

        public void Initialize()
        {
            MaterialProperties mp = m_body.CollisionSkin.GetMaterialProperties(0);
            mp.DynamicRoughness = 1.0f;
            mp.StaticRoughness = 1.0f;
            mp.Elasticity = 0.0f;
            m_body.CollisionSkin.SetMaterialProperties(0, mp);

            m_body.SetBodyInvInertia(0, 0, 0);
            m_body.Mass = 10.0f;
            m_body.EnableBody();
            m_body.AllowFreezing = false;
        }

    #endregion

    #region methods

        public void WorldMove(Vector3 move)
        {
            m_desiredVelocity = move * m_moveSpeed;
        }

        public void MoveTo(Vector3 position)
        {
            m_processMove = true;
            m_moveTo = position;
            
            Vector3 moveToXZ = new Vector3(m_moveTo.X, 0, m_moveTo.Z);
            Vector3 positionXZ = new Vector3(m_body.Position.X, 0, m_body.Position.Z);
            Vector3 travel = moveToXZ - positionXZ;
            m_distance = travel.Length();

            float adj = travel.X;
            float opp = travel.Z;
            float hyp = m_distance;

            float x, y;
            float angle = 0;

            x = (float)Math.Acos((double)(adj / hyp));
            y = (float)Math.Asin((double)(opp / hyp));

            angle = y <= 0 ? x : -x;
            angle = MathHelper.ToDegrees(angle);

            m_yawDirection = angle;
        }

        public void Jump()
        {
            m_doJump = true;
        }

        public override void UpdateController(float dt)
        {
            // move to
            if (m_processMove == true)
            {
                Vector3 moveToXZ = new Vector3(m_moveTo.X, 0, m_moveTo.Z);
                Vector3 positionXZ = new Vector3(m_body.Position.X, 0, m_body.Position.Z);
                Vector3 travel = moveToXZ - positionXZ;
                float distanceLeft = travel.Length();

                travel.Normalize();
                if (distanceLeft > m_distance)
                    m_processMove = false;
                m_desiredVelocity = travel * m_moveSpeed;
                m_distance = distanceLeft;
            }

            // normalize the max speed
            if (Math.Abs(m_desiredVelocity.X) > 5.0f)
                m_desiredVelocity.X = 5.0f * Math.Sign(m_desiredVelocity.X);
            if (Math.Abs(m_desiredVelocity.Z) > 5.0f)
                m_desiredVelocity.Z = 5.0f * Math.Sign(m_desiredVelocity.Z);

            // avoid the small jump when movement stop
            float velY = m_body.Velocity.Y;
            if ((m_desiredVelocity.X == 0) && (m_desiredVelocity.Z == 0))
                velY = Math.Sign(velY) > 0 ? 0 : velY;
            //if (m_body.Velocity.Y < 0)
            //    velY *= 5.0f;

            // apply the velocity to the body
            m_body.Velocity = new Vector3(m_desiredVelocity.X, velY, m_desiredVelocity.Z);
            base.UpdateController(dt);
        }

    #endregion

    }
}
